package serial;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Scanner;

public class LibraryChecker {

	private static final boolean debug = false;
	private static final String IN_MEMORY = "if write == nil then print(\"false\") else print(\"true\") end\n";
	
	public static String makeCheckerWith(String functionName) {
		return "if " + functionName + " == nil then print(\"false\") else print(\"true\") end\n";
	}
	
	public static String loadLibraryFrom(String filename) throws FileNotFoundException {
		Scanner s = new Scanner(new File(filename));
		String filetext = "";
		while (s.hasNextLine()) {
			filetext += s.nextLine() + "\n";
		}
		return filetext;
	}
	
	public static boolean isLibraryInPlace(String portName, String checkCmd) throws SerialException {
		return isLibraryIn(portName, checkCmd, "true");
	}
	
	public static void sendLibrary(String portName, String libraryName) throws SerialException, FileNotFoundException {
		String lib = loadLibraryFrom(libraryName);
		isLibraryIn(portName, lib, "(none)");
	}
	
	private static boolean isLibraryIn(String portName, String cmd, String targetResponse) throws SerialException {
		try {
			//if (debug) {System.out.println(cmd);}
			CmdSender.cmdToFile(cmd);
			Process p = Runtime.getRuntime().exec(CmdSender.makeCmd(portName, false));
			while (p.getInputStream().available() == 0 && p.getErrorStream().available() == 0) {}
			if (p.getInputStream().available() > 0) {
				String response = CmdSender.processOutput(p);
				if (debug) {System.out.println(response);}
				return CmdSender.responsePresentIn(response, targetResponse);
			} else {
				String error = CmdSender.processOutput(p);
				if (error.contains("No such file or directory")) {
					throw new NoSuchPortException();
				} else {
					throw new SerialException(error);
				}
			}

		} catch (IOException e) {
			throw new SerialException(e.getMessage());
		} catch (InterruptedException e) {
			throw new SerialException(e.getMessage());
		}
	}
	
	/*
	private static final boolean debug = false;
	
	private static final String IN_MEMORY = "if write == nil then print(\"false\") else print(\"true\") end\n";
	
	private static final String IN_FLASH = "if nxt.FileExists(\"gjflib1\") and nxt.FileExists(\"gjflib2\") and nxt.FileExists(\"gjflib3\") then\n  print(\"present\")\nelse\n  print(\"absent\")\nend\n";

	private static final String LOAD_FROM_FLASH = 
		"function readAndLoad(filename)\n" +
		"h = nxt.FileOpen(filename)\n" +
		"programString = nxt.FileRead(h, \"*a\")\n" +
		"nxt.FileClose(h)\n" +
		"a = loadstring(programString)\n" +
		"print(a)\n" +
		"a()\n" +
		"end\n" +
		"readAndLoad(\"gjflib1\")\nreadAndLoad(\"gjflib2\")\nreadAndLoad(\"gjflib3\")\n" +
		"write(\"Library loaded\", 8)\n" +
		"print(\"loaded\")\n";
	
	private static final String SAVE_IN_FLASH_1 = "filename = \"";
	private static final String SAVE_IN_FLASH_2 = "\"\nif nxt.FileExists(filename) then nxt.FileDelete(filename) end\ntext = [[";
	private static final String SAVE_IN_FLASH_3 = 
		"]]\nfile = nxt.FileCreate(filename, string.len(text))\n" + 
		"nxt.FileWrite(file, text)\n" + 
		"nxt.FileClose(file)\nprint(\"written\")\n";
	
	private static boolean isLibraryIn(String portName, String cmd, String targetResponse) throws SerialException {
		try {
			//if (debug) {System.out.println(cmd);}
			CmdSender.cmdToFile(cmd);
			Process p = Runtime.getRuntime().exec(CmdSender.makeCmd(portName, false));
			while (p.getInputStream().available() == 0 && p.getErrorStream().available() == 0) {}
			if (p.getInputStream().available() > 0) {
				String response = CmdSender.processOutput(p);
				if (debug) {System.out.println(response);}
				return CmdSender.responsePresentIn(response, targetResponse);
			} else {
				String error = CmdSender.processOutput(p);
				if (error.contains("No such file or directory")) {
					throw new NoSuchPortException();
				} else {
					throw new SerialException(error);
				}
			}

		} catch (IOException e) {
			throw new SerialException(e.getMessage());
		} catch (InterruptedException e) {
			throw new SerialException(e.getMessage());
		}
	}
	
	private static boolean isLibraryInMemory(String portName) throws SerialException {
		return isLibraryIn(portName, IN_MEMORY, "true");
	}
	
	private static boolean isLibraryInFlash(String portName) throws SerialException {
		return isLibraryIn(portName, IN_FLASH, "present");
	}
	
	public static boolean isLibraryInPlace(String portName) throws SerialException {
		if (isLibraryInMemory(portName)) {
			return true;
		} else if (isLibraryInFlash(portName)) {
			System.out.println("About to load from flash");
			return isLibraryIn(portName, LOAD_FROM_FLASH, "loaded");
		} else {
			return false;
		}
	}
	
	public static String loadLibraryFrom(String filename) throws FileNotFoundException {
		Scanner s = new Scanner(new File(filename));
		String filetext = "";
		while (s.hasNextLine()) {
			filetext += s.nextLine() + "\n";
		}
		return filetext;
	}
	
	public static void sendLibraryToFlash(String portName) throws SerialException, FileNotFoundException {
		sendLibraryFileToFlash(portName, "gjflib1");
		sendLibraryFileToFlash(portName, "gjflib2");
		sendLibraryFileToFlash(portName, "gjflib3");
	}
	
	private static void sendLibraryFileToFlash(String port, String filename) throws SerialException, FileNotFoundException {
		String filetext = loadLibraryFrom(filename);
		String cmd = SAVE_IN_FLASH_1 + filename + SAVE_IN_FLASH_2 + filetext + SAVE_IN_FLASH_3;
		isLibraryIn(port, cmd, "written");
	}
	
	public static void main(String[] args) throws SerialException {
        System.out.println(isLibraryInPlace(args[0]));
    }
    */
}
